package com.ctgu.server.utils;

import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.util.Arrays;

import java.security.SecureRandom;

public class SHA256Utils {
    /**
    * 盐值的长度，以字节为单位。在这个示例中，盐值的长度为16字节，即128位。盐值用于增加密码的安全性，使相同的输入生成不同的哈希结果。
    * */
    private static final int SALT_LENGTH = 8; // 盐值长度（以字节为单位）

    /**
    * 迭代次数。在哈希计算过程中，使用盐值和输入数据进行一系列迭代操作以增加计算的复杂性和时间成本，提高密码的安全性。
    * */
    private static final int ITERATIONS = 1000; // 迭代次数

    /**
    * max 256
    * 密钥的长度，以位为单位。在这个示例中，密钥的长度为256位。密钥是从哈希计算结果中派生出来的关键部分，用于加密和解密数据。较长的密钥长度可以提供更高的安全性。
    * */
    private static final int KEY_LENGTH = 64; // 密钥长度（以位为单位）

    /**
     * 使用SHA-256算法对输入进行加密
     *
     * @param input 输入字符串
     * @return 加密后的字符串
     */
    public static String encrypt(String input) {
        byte[] salt = generateSalt();
        byte[] encryptedData = hash(input.getBytes(), salt);
        byte[] result = Arrays.concatenate(salt, encryptedData);
        return bytesToHex(result);
    }

    /**
     * 使用SHA-256算法对输入进行验证
     *
     * @param input    输入字符串
     * @param hashData 加密后的字符串
     * @return 验证结果，true表示验证通过，false表示验证失败
     */
    public static boolean verify(String input, String hashData) {
        byte[] data = hexToBytes(hashData);
        byte[] salt = Arrays.copyOfRange(data, 0, SALT_LENGTH);
        byte[] storedHash = Arrays.copyOfRange(data, SALT_LENGTH, data.length);
        byte[] currentHash = hash(input.getBytes(), salt);
        return Arrays.areEqual(storedHash, currentHash);
    }

    /**
     * 生成随机的盐值
     *
     * @return 盐值的字节数组
     */
    private static byte[] generateSalt() {
        SecureRandom random = new SecureRandom();
        byte[] salt = new byte[SALT_LENGTH];
        random.nextBytes(salt);
        return salt;
    }

    /**
     * 使用SHA-256算法对输入数据进行哈希计算
     *
     * @param input 输入数据的字节数组
     * @param salt  盐值的字节数组
     * @return 哈希计算结果的字节数组
     */
    private static byte[] hash(byte[] input, byte[] salt) {
        PKCS5S2ParametersGenerator generator = new PKCS5S2ParametersGenerator(new SHA256Digest());
        generator.init(input, salt, ITERATIONS);
        KeyParameter key = (KeyParameter) generator.generateDerivedParameters(KEY_LENGTH);
        return key.getKey();
    }

    /**
     * 将字节数组转换为十六进制字符串
     *
     * @param bytes 字节数组
     * @return 十六进制字符串
     */
    private static String bytesToHex(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            String hex = Integer.toHexString(0xFF & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }

    /**
     * 将十六进制字符串转换为字节数组
     *
     * @param hex 十六进制字符串
     * @return 字节数组
     */
    private static byte[] hexToBytes(String hex) {
        int length = hex.length();
        byte[] bytes = new byte[length / 2];
        for (int i = 0; i < length; i += 2) {
            bytes[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
                    + Character.digit(hex.charAt(i + 1), 16));
        }
        return bytes;
    }
}
